/*
 * File_Name RSAUtil.java
 * version 
 * copyright (c)2018 Asiainfo Network Security Group Security Innovative Operation Dept. All rights reserved.
 */
package com.j.lemon.learn.enc;


import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jcajce.provider.asymmetric.rsa.RSAUtil;
import org.springframework.stereotype.Component;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA 加密是一种非对称加密算法，是由三位数学家 Rivest、Shamir 和 Adleman 于 1977 年提出的。与对称加密算法不同，RSA 加密算法使用公钥和私钥两个不同的密钥来加密和解密数据，因此也被称为公钥加密算法。
 *
 * ---------------------------------------------------------------------------------------------
 *
 * RSA和AES的区别：
 * RSA 和 AES 都是加密算法，但它们的作用不同，应用场景也不同。
 * RSA 是一种非对称加密算法，用于在网络上的通信中实现加密和数字签名。RSA 通过两个密钥（公钥和私钥）来进行加密和解密操作，公钥用于加密，私钥用于解密。RSA 主要应用在数字证书、SSL/TLS、SSH、PGP 等安全协议中。
 * AES 是一种对称加密算法，用于对数据进行加密和解密操作。AES 使用同一个密钥来进行加密和解密操作，因此称为对称加密算法。AES 通常用于在本地存储设备上加密数据，以保护数据的机密性。
 * 在实际应用中，RSA 和 AES 经常结合使用。例如，可以使用 RSA 加密 AES 密钥，然后使用 AES 加密数据，这样可以充分发挥 RSA 和 AES 各自的优势。通过 RSA 加密 AES 密钥，可以确保 AES 密钥的安全性，而使用 AES 加密数据，则可以保护数据的机密性。这种结合使用的方式被广泛应用在各种网络安全协议中，如 SSL/TLS、HTTPS 等。
 *
 * ---------------------------------------------------------------------------------------------
 *
 * RSA和AES互相结合的好处：
 * RSA加密速度慢，适用于小数据量的加密，AES加密速度快
 *
 * ---------------------------------------------------------------------------------------------
 *
 * AES和DES的区别：
 * DES使用56位密钥加密，1999年被证明不够安全，被AES取代。
 *
 * ---------------------------------------------------------------------------------------------
 *
 * 3DES是什么加密算法：
 * 3DES是Triple Data Encryption Standard的缩写，也叫作TDES或Triple DES，是DES的升级版。它使用三个56位的DES密钥，通过加密-解密-加密（EDE）的方式进行加密。在加密过程中，数据先被第一个密钥加密，然后使用第二个密钥进行解密，最后使用第三个密钥进行加密。3DES的密钥长度为168位，比DES的56位更加安全。
 * 但仍推荐AES
 *
 * ---------------------------------------------------------------------------------------------
 *
 * MD5、SHA-1、SHA-256是hash算法，区别：
 *
 * MD5、SHA-1和SHA-256都是哈希算法，用于将任意长度的消息（message）映射为固定长度的摘要（digest），通常用于确保数据完整性和验证身份。
 * 它们的区别在于以下几个方面：
 *
 * 摘要长度：MD5的摘要长度为128位，SHA-1的摘要长度为160位，SHA-256的摘要长度为256位。摘要长度越长，碰撞（collision）的概率越小，安全性越高。
 * 碰撞攻击：MD5已经被证明存在碰撞攻击漏洞，即可以构造出两个不同的消息，但它们的MD5摘要相同。SHA-1也存在碰撞攻击漏洞，但相较于MD5，它的安全性更高。SHA-256目前尚未出现碰撞攻击漏洞。
 * 处理速度：MD5的处理速度最快，SHA-1次之，SHA-256最慢。然而，随着硬件技术的发展，SHA-256的速度也得到了大幅提升，而MD5和SHA-1的处理速度已经不再是选择它们的主要原因。
 * 因此，在实际应用中，由于MD5和SHA-1存在安全漏洞，建议使用更为安全的哈希算法，如SHA-256或更高版本的SHA。
 *
 * ---------------------------------------------------------------------------------------------
 *
 * 国密是指由中国密码学家自主研发的密码算法，包括SM1、SM2、SM3和SM4等一系列算法。
 * 其中，
 * SM1是一种对称加密算法，适用于加密小数据量；
 * SM2是一种非对称加密算法，适用于数字签名和密钥交换；
 * SM3是一种哈希算法，适用于数字签名和消息认证；
 * SM4是一种对称加密算法，适用于数据加密。
 * @author lijunjun
 */
@Component
public class Rsa {
    public static void main(String[] args) throws Exception {
//        //生成公私钥对
//        // 选择算法
//        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
//
//        // 设置密钥长度
//        keyPairGenerator.initialize(2048);
//
//        // 生成密钥对
//        KeyPair keyPair = keyPairGenerator.generateKeyPair();
//
//        // 获取私钥和公钥
//        PrivateKey privateKey = keyPair.getPrivate();
//        PublicKey publicKey = keyPair.getPublic();
//        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
//        byte[] encoded = pkcs8EncodedKeySpec.getEncoded();
//        String s = Base64.encodeBase64String(encoded);
//        System.out.println("私钥："+s);
//
//
//        PKCS8EncodedKeySpec publicd = new PKCS8EncodedKeySpec(publicKey.getEncoded());
//        byte[] pencoded = publicd.getEncoded();
//        String s1 = Base64.encodeBase64String(pencoded);
//        System.out.println("公钥："+s1);

//        ===============================================================
//        String privateK = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCprbvfLMlaxaDaXvne1rgOqF9c8yBkusIdAfxvClQofLXudJiTdhUBSpimqWx/nVU0EB8Yz1OxNRRt7jQJgSwfN4DOZMB0/XT80bKBxHirlHuexzCEma1AK9U0nxJnZrARukTQYNN+WqloMiZKBoYEQvn3aDHRA3V09JhWHpcVBIS9XH445kVhCY0o8giA8ENPj/u+cbk6iAgFyK6jrxi1ZBTJIpXkcDFdVtJmxMANXbmr6+eHD18Si5bMrVDrH8I9tCTcL+p5UjmTUAgcpvRXQnSDupYKUo+4lImqBYvEi6uQaZbjttiilW3KzIuZJ1OaVGYp8v/rPJ1Df05hLBjJAgMBAAECggEAB+18F6NKDRmquEkzt3ukwdqQChG587reEuji2HVNFU8uWOPNtSYROSw5EaBc12GMd5BBQ7F8IY1vVOuKNt94JkU7mWkPrOeiraVGh9WcJbgcRoDb/XYIqDTkEz9TZs1fcJSZXnsHpqGpxJqDO3YukMhoUWzm1vMoa7x52Zw4Rt0Js3Kzg4hG6Zq332jMGY1Pa+oYWeoQwhwBHMplDepLiLI5W9EURqBeuJz38FTvXq/hfSGTI4jW0ACQk44gvYf/2WU0YKWv1NiA7uQ7Jt7GZx5e802SCcD4LBL+B2qv2XFB20mD5MNtc8jDFE2ET5bxNzBb5kH/Bm2dRutKROkxAQKBgQDVjGkoyHy1RbGevNMorTQ3K9A4oqTT2p3KUpIQBO34dYrPXKNtYdn847MN+W6dXRnim+RKLiMdMGZFMMoWFZacwo9bRWIgJGBg9EOORHaYRxGZ7rkJVi3qGoxyjI4V8ZfaNIhxsesiLryhz4cG+MWeEgkai7SFJ+Xjli56B2Y00QKBgQDLaMPuwIYeacvaLdyzJw4RDbe2u/QiZF2ugEFVheT0hkPHrYFTAZzyrdXiapaJYz5Os3kg2YKNDtfaCwYm9uqD1q/tDNl0ghBMDCPhwfS54KNjOH6ts2Pb36Xtx6Cnzy5mdy/4W9KM4gVetCg0cJ8s6PpGN0A2K8rLW1W/GRuCeQKBgQDFOhklgYUsJmIVqW+ccdt32Q9GP3Db+V0iL4CXKvZeMrExMu39aBJcbjBBB84RqJrvn+sIV/Q2US0jWhxKqUWhIlAki8BEz1P0N6TtEG431et7r+9VoDJntH1ijk3sFmWZMkuSNjBkMaYmC/U5iyl5BE9EJSNkl6TKvTnPmmXbAQKBgDjaqZk8OsCZdZ8gHoX8rpPZr7XlxxEt2HmD478R07L9LEjNmE4pL0Mtj5DflgAEu0+oHn0uDq16rp6FYkzVyyragQXTB5znFcMLyaO6YLrrrP94tP+8GndEhc52c9Mzt5ZwTfovQCScsD+OP4aYzATzgbDKlKoPh3lbqBXn4KaRAoGADT/ov5V+27RCBtZ7HdaKLg6X5c311rs6Z7tu1oTGbgJIsBUWYpOg91RZ8EQ2Hr4b018uXAAO1PSjSvzqAS9RXKCX7zaLNfRkEix6AOVG0dZzsApdla8LfB+lJ5fyVVIl0JNIOvrH9K2IajdK2iLI2f22a658MiAk2EdZFksBqIY=";
//        String publicK = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqa273yzJWsWg2l753ta4DqhfXPMgZLrCHQH8bwpUKHy17nSYk3YVAUqYpqlsf51VNBAfGM9TsTUUbe40CYEsHzeAzmTAdP10/NGygcR4q5R7nscwhJmtQCvVNJ8SZ2awEbpE0GDTflqpaDImSgaGBEL592gx0QN1dPSYVh6XFQSEvVx+OOZFYQmNKPIIgPBDT4/7vnG5OogIBciuo68YtWQUySKV5HAxXVbSZsTADV25q+vnhw9fEouWzK1Q6x/CPbQk3C/qeVI5k1AIHKb0V0J0g7qWClKPuJSJqgWLxIurkGmW47bYopVtysyLmSdTmlRmKfL/6zydQ39OYSwYyQIDAQAB";
//        //AES密钥的长度必须是16、24或32字节，分别对应于AES-128、AES-192和AES-256加密算法
//        String a123 = enc(publicK, "qweasdzxcrfvtgby");
//        System.out.println("加密后AESKey："+a123);
//
//        String dec = dec(privateK, a123);
//        System.out.println("解密后AESKey："+dec);
//        ======================================================
//
//        String s = aesEnc(dec, "Ab,123456");
//        System.out.println("aes加密后："+s);
//
//        String s1 = aesDec(dec, s);
//        System.out.println("aes解密后："+s1);
//        String privateK = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMwsEBrWBTSR8Ok3MoEArjQtE5c94MckNUGYogtZ3RX+PgLXTZbCXZ3bPJbBnVAZUnlxpAIChnmFtV54 +7OSLf29cSdI7wq9P0i1SZ4UopUk+hWciH3HUDR0/uTkMgkVACHRwnzOufDbCuvCtTuKnh62FdUfo08WfEs4i0StekirAgMBAAECgYANUkKqvZQRXgRN8yAEcrrrBJXmpE7qL16aLQ9FllNqf/Aj11BkqcHZ7tgBLhjJhR1wdw2wY+HKRAMVaudhTARcEArbpvau6Jb17i+6KXoREvbcYmxGgOZVDsqHu714pKRDrrDozU5jdx2lLjGpNLOhcoarABvmT/yWPqOwOLldgQJBAOwXG4YRH6Zt4uRDL3sucMHmsCSSR4bfeWv7LDmjtTiRp/P6i9Kx1z65wUQ85psuj/UayYA+ZFeSjTOW3/A62jECQQDdY+H7uO1JtueLPQMAp3oOyLgC0YRAJp2DLAqrrmT6En9v03dv/I8adFnrgEU6V3s6Jg9JukPWcpbKpW9AYr2bAkEAj9U4IIKYLLXvsC86YyqU6ZzYnT89Mm89s0qP1AHnqzIaB6sRumg8gWt70k3kFJDWhXYvYuEgErYnLlHx1pKUUQJBAMiTCJcVSK3DLu2gHgtGsDeas9Oh3E5+ba/8g8Jc4pEJlzlJ/eiQiVnvVdQdxxp/TV42Qx2JypIMCP+ZeDx9+McCQCTnFV3DM6MXpLuN+tbMHNuDOvNv6NRa4Q0Md9nn4T5EYKb0+KAlhCqu9p3AYsWkQIrMSPq4dzJZuuCsPX3ciiM=";
//        String e = "FjG62qTm2aEHxhQboAOLgA7IkBdkhpQGId29RZ7+TXTmR93deHpp3T3m4Y4rbKmwNlnrZrspHEloQqehD1ds6QvB5RB7As9RjPzhjfFpzyZjQhKA3hgOuqi4VY2ZJPOM0o3ra6yl9CT7Oy4LxPomG+LOHUIAltFD0bSxmpBFHS8=";
//        String dec = dec(privateK, e);
//        System.out.println(dec);

    }

    public static String enc(String publicKey,String aesSec) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        Cipher cipher = Cipher.getInstance("RSA");
        byte[] decode = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec pkcs8EncodedKeySpec = new X509EncodedKeySpec(decode);
        PublicKey rsa = KeyFactory.getInstance("RSA").generatePublic(pkcs8EncodedKeySpec);
        cipher.init(Cipher.ENCRYPT_MODE,rsa);
        byte[] bytes = cipher.doFinal(aesSec.getBytes(StandardCharsets.UTF_8));
        String s = Base64.encodeBase64String(bytes);
        return s;
    }

    public static String dec(String privateKeyStr,String aesSec) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        byte[] decode = Base64.decodeBase64(privateKeyStr);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(decode);
        PrivateKey pk = KeyFactory.getInstance("RSA").generatePrivate(pkcs8EncodedKeySpec);


        byte[] bytes = Base64.decodeBase64(aesSec);
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE,pk);

        byte[] bytes1 = cipher.doFinal(bytes);
        return new String(bytes1, StandardCharsets.UTF_8);
    }

    public static String aesEnc(String sec,String password) throws Exception{
        byte[] secBytes = sec.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec secretKeySpec = new SecretKeySpec(secBytes,0,secBytes.length,"AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);
        byte[] bytes = cipher.doFinal(password.getBytes(StandardCharsets.UTF_8));
        return Base64.encodeBase64String(bytes);
    }

    public static String aesDec(String sec,String password)throws Exception{
        byte[] secBytes = sec.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec secretKeySpec = new SecretKeySpec(secBytes,0,secBytes.length,"AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE,secretKeySpec);
        byte[] bytes1 = Base64.decodeBase64(password);
        byte[] bytes2 = cipher.doFinal(bytes1);
        return new String(bytes2,StandardCharsets.UTF_8);
    }

}
